package org.microframework.base.core.datasource.aop;

import com.jfinal.plugin.activerecord.ActiveRecordException;
import com.jfinal.plugin.activerecord.Config;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.NestedTransactionHelpException;
import com.jfinal.plugin.activerecord.tx.TxConfig;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.microframework.base.core.datasource.annotation.Tx;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.*;

/**
 * JFinal事务AOP处理器
 * 拦截带有@Tx注解的方法，提供事务管理能力
 */
@Slf4j
@Aspect
@Component
@Order(1) // 确保事务切面优先级高于其他切面
public class JFinalTxAop {

    /**
     * 定义切点：拦截带有@Tx注解的方法
     */
    @Pointcut("@annotation(org.microframework.base.core.datasource.annotation.Tx)")
    private void txMethods() {
        // 切点定义，不需要实现
    }

    /**
     * 环绕通知，处理事务逻辑
     * @param pjp 连接点
     * @return 方法执行结果
     * @throws Throwable 执行异常
     */
    @Around("txMethods()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        // 获取方法上的Tx注解
        MethodSignature ms = (MethodSignature) pjp.getSignature();
        Method method = ms.getMethod();
        Tx tx = method.getAnnotation(Tx.class);
        
        // 获取事务配置
        Config config = getConfigWithTxConfig(pjp);
        if (config == null) {
            config = DbKit.getConfig();
        }

        // 检查是否已存在事务连接（处理嵌套事务情况）
        Connection conn = config.getThreadLocalConnection();
        if (conn != null) {
            return handleExistingTransaction(pjp, config, conn);
        }

        // 创建新事务
        return handleNewTransaction(pjp, config, tx);
    }

    /**
     * 处理已存在事务的情况
     */
    private Object handleExistingTransaction(ProceedingJoinPoint pjp, Config config, Connection conn) throws Throwable {
        try {
            // 如果现有连接的隔离级别低于配置的隔离级别，则提升隔离级别
            int requiredLevel = getTransactionLevel(config);
            if (conn.getTransactionIsolation() < requiredLevel) {
                conn.setTransactionIsolation(requiredLevel);
            }
            // 在现有事务中执行
            return pjp.proceed();
        } catch (SQLException e) {
            throw new ActiveRecordException(e);
        }
    }

    /**
     * 处理新事务的情况
     */
    private Object handleNewTransaction(ProceedingJoinPoint pjp, Config config, Tx tx) throws Throwable {
        Connection conn = null;
        Boolean autoCommit = null;
        
        try {
            // 获取新连接并配置
            conn = config.getConnection();
            autoCommit = conn.getAutoCommit();
            config.setThreadLocalConnection(conn);
            conn.setTransactionIsolation(getTransactionLevel(config));
            conn.setAutoCommit(false);
            
            // 执行业务方法，支持超时控制
            Object result;
            int timeout = tx != null ? tx.timeout() : -1;
            if (timeout > 0) {
                result = executeWithTimeout(pjp, timeout);
            } else {
                result = pjp.proceed();
            }
            
            // 提交事务
            conn.commit();
            return result;
        } catch (NestedTransactionHelpException e) {
            // 处理嵌套事务辅助异常（JFinal内部机制）
            rollbackQuietly(conn);
            log.error("嵌套事务辅助异常: {}", e.getMessage(), e);
            throw e;
        } catch (TimeoutException e) {
            // 处理事务超时异常
            rollbackQuietly(conn);
            log.error("事务执行超时，已回滚事务", e);
            throw new RuntimeException("事务执行超时", e);
        } catch (Throwable t) {
            // 处理其他异常并回滚
            rollbackQuietly(conn);
            throw t instanceof RuntimeException ? (RuntimeException) t : new ActiveRecordException(t);
        } finally {
            // 清理连接资源
            closeConnection(conn, autoCommit, config);
        }
    }
    
    /**
     * 使用超时控制执行方法
     * @param pjp 连接点
     * @param timeoutSeconds 超时时间（秒）
     * @return 方法执行结果
     * @throws Throwable 执行异常
     */
    private Object executeWithTimeout(final ProceedingJoinPoint pjp, int timeoutSeconds) throws Throwable {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Object> future = executor.submit(() -> {
            try {
                return pjp.proceed();
            } catch (Throwable e) {
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                } else {
                    throw new RuntimeException(e);
                }
            }
        });
        
        try {
            return future.get(timeoutSeconds, TimeUnit.SECONDS);
        } finally {
            executor.shutdownNow(); // 立即关闭执行器
        }
    }

    /**
     * 安静地回滚事务（不抛出异常）
     */
    private void rollbackQuietly(Connection conn) {
        if (conn != null) {
            try {
                conn.rollback();
            } catch (Exception e) {
                log.error("事务回滚失败: {}", e.getMessage(), e);
            }
        }
    }

    /**
     * 关闭连接并恢复设置
     */
    private void closeConnection(Connection conn, Boolean autoCommit, Config config) {
        try {
            if (conn != null) {
                if (autoCommit != null) {
                    conn.setAutoCommit(autoCommit);
                }
                conn.close();
            }
        } catch (Throwable t) {
            // 不能在这里抛出异常，否则会掩盖更重要的前面catch块中的异常
            log.error("关闭数据库连接失败: {}", t.getMessage(), t);
        } finally {
            // 防止内存泄漏
            config.removeThreadLocalConnection();
        }
    }

    /**
     * 获取配置的事务隔离级别
     * @param config 数据库配置
     * @return 事务隔离级别
     */
    protected int getTransactionLevel(Config config) {
        return config.getTransactionLevel();
    }

    /**
     * 获取TxConfig注解配置的数据源
     * @param pjp 连接点
     * @return 数据库配置
     */
    private static Config getConfigWithTxConfig(ProceedingJoinPoint pjp) {
        MethodSignature ms = (MethodSignature) pjp.getSignature();
        Method method = ms.getMethod();
        
        // 先从方法上获取TxConfig注解
        TxConfig txConfig = method.getAnnotation(TxConfig.class);
        
        // 如果方法上没有，则从类上获取
        if (txConfig == null) {
            txConfig = pjp.getTarget().getClass().getAnnotation(TxConfig.class);
        }

        // 如果找到了TxConfig注解，根据其值获取对应的Config
        if (txConfig != null) {
            Config config = DbKit.getConfig(txConfig.value());
            if (config == null) {
                throw new RuntimeException("数据源配置未找到: " + txConfig.value());
            }
            return config;
        }
        
        // 获取方法上的Tx注解，看是否指定了数据源
        Tx tx = method.getAnnotation(Tx.class);
        if (tx != null && !tx.value().isEmpty()) {
            Config config = DbKit.getConfig(tx.value());
            if (config == null) {
                throw new RuntimeException("数据源配置未找到: " + tx.value());
            }
            return config;
        }
        
        return null;
    }
}
